{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": [],
      "authorship_tag": "ABX9TyPhSLU0gfdI98tZdjQ8iL1l",
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/nceder/qpb4e/blob/main/code/Chapter%2011/Chapter_11.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 11 Python programs"
      ],
      "metadata": {
        "id": "reyZ3JJDBYsw"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 11.1 Creating a very basic program"
      ],
      "metadata": {
        "id": "n1TIhuWIBk3i"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!wget https://raw.githubusercontent.com/nceder/qpb4e/main/code/Chapter%2011/script1.py &> null  && echo Downloaded"
      ],
      "metadata": {
        "id": "6rQ7I-A6xbQc",
        "outputId": "2b093ddf-ae76-4b12-8ef5-0361c257337e",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 1,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloaded\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "YZfFO8MHjB98",
        "outputId": "1859c5e8-a74f-4d98-bc9e-430dfdcc3d6a",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "this is our first test script file\n"
          ]
        }
      ],
      "source": [
        "# Listing 11.1 File script1.py\n",
        "\n",
        "def main():                              #A\n",
        "    print(\"this is our first test script file\")\n",
        "main()"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "! python script1.py"
      ],
      "metadata": {
        "id": "Ws3d0AaJ1M37",
        "outputId": "32e739be-4b27-4d91-9fe0-5e680dd597ec",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 3,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "this is our first test script file\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## 11.1.2 Command-line arguments"
      ],
      "metadata": {
        "id": "Yr2QiEZDBxzB"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!wget https://raw.githubusercontent.com/nceder/qpb4e/main/code/Chapter%2011/script2.py &> null  && echo Downloaded"
      ],
      "metadata": {
        "id": "MqCA_s8S1SWd",
        "outputId": "d9235415-e8c2-404f-b5ae-78d44870a4f7",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 4,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloaded\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "```python\n",
        "# Listing 11.2 File script2.py\n",
        "\n",
        "import sys\n",
        "def main():\n",
        "    print(\"this is our second test script file\")\n",
        "    print(sys.argv)\n",
        "main()\n",
        "```"
      ],
      "metadata": {
        "id": "hmtrHPFlJTfH"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "! python script2.py arg1 arg2 3"
      ],
      "metadata": {
        "id": "XeT40bLv1W7e",
        "outputId": "712d4421-e71b-4910-ccbd-5206c3a11107",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 5,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "this is our second test script file\n",
            "['script2.py', 'arg1', 'arg2', '3']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## 11.1.4 Redirecting the input and output of a script"
      ],
      "metadata": {
        "id": "twLeeUMXB58x"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!wget https://raw.githubusercontent.com/nceder/qpb4e/main/code/Chapter%2011/replace.py &> null  && echo Downloaded\n",
        "open(\"infile\", \"w\").write(\"This line has the word zero and the number 0.\")"
      ],
      "metadata": {
        "id": "fBh8doS91g5w",
        "outputId": "09acf1c5-cda0-4488-898d-d395f2a245be",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 6,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloaded\n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "45"
            ]
          },
          "metadata": {},
          "execution_count": 6
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "```python\n",
        "#Listing 11.3 File replace.py\n",
        "\n",
        "import sys\n",
        "def main():\n",
        "   contents = sys.stdin.read()                     #A\n",
        "   sys.stdout.write(contents.replace(sys.argv[1], sys.argv[2]))  #B\n",
        "if __name__ == \"__main__\":\n",
        "   main()\n",
        "```\n"
      ],
      "metadata": {
        "id": "UFAvhdcfJJwT"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "! python replace.py zero 0 < infile > outfile\n",
        "\n",
        "! cat outfile\n"
      ],
      "metadata": {
        "id": "Wqx_sSWr15Gx",
        "outputId": "f1b96b2e-a182-4946-b716-2b95f402ab95",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 7,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "This line has the word 0 and the number 0."
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 11.1.5 The argparse module"
      ],
      "metadata": {
        "id": "ZyC1NkQMIvat"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!wget https://raw.githubusercontent.com/nceder/qpb4e/main/code/Chapter%2011/opts.py &> null  && echo Downloaded"
      ],
      "metadata": {
        "id": "m-NW2dWy16I0",
        "outputId": "145564fa-68aa-47a6-aeae-2243cee47957",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 8,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloaded\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "```python\n",
        "# Listing 11.4 File opts.py\n",
        "\n",
        "from argparse import ArgumentParser\n",
        "\n",
        "def main():\n",
        "    parser = ArgumentParser()\n",
        "    parser.add_argument(\"indent\", type=int, help=\"indent for report\")\n",
        "    parser.add_argument(\"input_file\", help=\"read data from this file\")   #1\n",
        "    parser.add_argument(\"-f\", \"--file\", dest=\"filename\",             #2\n",
        "                  help=\"write report to FILE\", metavar=\"FILE\")\n",
        "    parser.add_argument(\"-x\", \"--xray\",\n",
        "                  help=\"specify xray strength factor\")\n",
        "    parser.add_argument(\"-q\", \"--quiet\",\n",
        "                  action=\"store_false\", dest=\"verbose\", default=True, #3\n",
        "                  help=\"don't print status messages to stdout\")\n",
        "\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    print(\"arguments:\", args)\n",
        "\n",
        "if __name__ == \"__main__\":\n",
        "    main()\n",
        "```"
      ],
      "metadata": {
        "id": "-JeD7bDQI51b"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "! python opts.py -x100 -q -f outfile 2 arg2"
      ],
      "metadata": {
        "id": "utsB4KIL2Xhc",
        "outputId": "16137777-8a13-4879-bd5f-cf37f804a29b",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 9,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "arguments: Namespace(indent=2, input_file='arg2', filename='outfile', xray='100', verbose=False)\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## 11.1.6 Using the fileinput module"
      ],
      "metadata": {
        "id": "kZgJ9klbJn-O"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "open(\"sole1.tst\", \"w\").write(\n",
        "    \"\"\"## sole1.tst: test data for the sole function\n",
        "0 0 0\n",
        "0 100 0\n",
        "##\"\"\"\n",
        ")\n",
        "open(\"sole2.tst\", \"w\").write(\n",
        "    \"\"\"## sole2.tst: more test data for the sole function\n",
        "12 15 0\n",
        "##\n",
        "100 100 0\"\"\"\n",
        ")\n",
        "\n",
        "!wget https://raw.githubusercontent.com/nceder/qpb4e/main/code/Chapter%2011/script4.py  &> null  && echo Downloaded"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Bwwf7Mzgkikg",
        "outputId": "dbbd7479-eee9-4cff-e778-36a7be19638a"
      },
      "execution_count": 10,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloaded\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "```python\n",
        "# Listing 11.5 File script4.py\n",
        "\n",
        "import fileinput\n",
        "def main():\n",
        "    for line in fileinput.input():\n",
        "        if not line.startswith('##'):\n",
        "            print(line, end=\"\")\n",
        "if __name__ == \"__main__\":\n",
        "    main()\n",
        "```"
      ],
      "metadata": {
        "id": "P1DG6KcRKNLj"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "! python script4.py sole1.tst sole2.tst"
      ],
      "metadata": {
        "id": "WU8HQMOU5gy3",
        "outputId": "a2903b46-e520-41b7-e03b-3751895bfd76",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 11,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "0 0 0\n",
            "0 100 0\n",
            "12 15 0\n",
            "100 100 0"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!wget https://raw.githubusercontent.com/nceder/qpb4e/main/code/Chapter%2011/script5.py &> null  && echo Downloaded"
      ],
      "metadata": {
        "id": "y7qQkQkW8l81",
        "outputId": "879d6119-e586-46c2-a56e-96513e53827c",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 12,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloaded\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "```python\n",
        "# Listing 11.8 File script5.py\n",
        "\n",
        "import fileinput\n",
        "def main():\n",
        "    for line in fileinput.input():\n",
        "        if fileinput.isfirstline():\n",
        "            print(\"<start of file {0}>\".format(fileinput.filename()))\n",
        "        print(line, end=\"\")\n",
        "if __name__ == \"__main__\":\n",
        "    main()\n",
        "```"
      ],
      "metadata": {
        "id": "A7TDd8bIKa4j"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "! python script5.py sole1.tst sole2.tst"
      ],
      "metadata": {
        "id": "jAriJUQm8qFR",
        "outputId": "fae0302d-4fab-48d8-f7af-bbf24d397936",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 13,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "<start of file sole1.tst>\n",
            "## sole1.tst: test data for the sole function\n",
            "0 0 0\n",
            "0 100 0\n",
            "##<start of file sole2.tst>\n",
            "## sole2.tst: more test data for the sole function\n",
            "12 15 0\n",
            "##\n",
            "100 100 0"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Quick Check: Scripts and arguments\n",
        "Match the following ways of interacting with the command line and the correct use case for each:\n",
        "\n",
        "|                                    |                                     |\n",
        "|------------------------------------|-------------------------------------|\n",
        "| Multiple argurments and options    | sys.agrv                            |\n",
        "| No arguments or just one argument  | Use fileinput module                |\n",
        "| Processing multiple files          | Redirect standard input and output  |\n",
        "| Using the script as a filter       |\tUse argparse module                |\n"
      ],
      "metadata": {
        "id": "FZdtDi84NhWf"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### Solution\n",
        "\n",
        "|                                    |                                     |\n",
        "|------------------------------------|-------------------------------------|\n",
        "| Multiple argurments and options    | Use argparse module                 |\n",
        "| No arguments or just one argument  | sys.argv                            |\n",
        "| Processing multiple files          | Use fileinput module                |\n",
        "| Using the script as a filter       | Redirect standard input and output  |\n"
      ],
      "metadata": {
        "id": "gg2ap4XFPj8s"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Try This: Making a script executable\n",
        "\n",
        "Experiment with executing scripts on your platform. Also try to redirect input and output into and out of your scripts."
      ],
      "metadata": {
        "id": "QWUUf9H-MqYH"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 11.3 Programs and modules"
      ],
      "metadata": {
        "id": "JmkQ4V8qK1pv"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!wget https://raw.githubusercontent.com/nceder/qpb4e/main/code/Chapter%2011/script6.py  &> null  && echo Downloaded"
      ],
      "metadata": {
        "id": "C22VSUUF9PVn",
        "outputId": "0f052566-d1d1-4e67-9c9e-67e8890620d2",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 15,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloaded\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "```python\n",
        "# Listing 11.9 File script6.py\n",
        "\n",
        "#! /usr/bin/env python3\n",
        "import sys\n",
        "# conversion mappings\n",
        "_1to9dict = {'0': '', '1': 'one', '2': 'two', '3': 'three', '4': 'four',\n",
        "             '5': 'five', '6': 'six', '7': 'seven', '8': 'eight',\n",
        "             '9': 'nine'}\n",
        "_10to19dict = {'0': 'ten', '1': 'eleven', '2': 'twelve',\n",
        "               '3': 'thirteen', '4': 'fourteen', '5': 'fifteen',\n",
        "               '6': 'sixteen', '7': 'seventeen', '8': 'eighteen',\n",
        "               '9': 'nineteen'}\n",
        "_20to90dict = {'2': 'twenty', '3': 'thirty', '4': 'forty', '5': 'fifty',\n",
        "               '6': 'sixty', '7': 'seventy', '8': 'eighty', '9': 'ninety'}\n",
        "def num2words(num_string):\n",
        "    if num_string == '0':\n",
        "        return'zero'\n",
        "    if len(num_string) > 2:\n",
        "        return \"Sorry can only handle 1 or 2 digit numbers\"\n",
        "    num_string = '0' + num_string                   #A\n",
        "    tens, ones = num_string[-2], num_string[-1]\n",
        "    if tens == '0':\n",
        "        return _1to9dict[ones]\n",
        "    elif tens == '1':\n",
        "        return _10to19dict[ones]\n",
        "    else:\n",
        "        return _20to90dict[tens] + ' ' + _1to9dict[ones]\n",
        "def main():\n",
        "    print(num2words(sys.argv[1]))        #1\n",
        "if __name__ == \"__main__\":\n",
        "    main()\n",
        "```"
      ],
      "metadata": {
        "id": "_NtxH4xjLClY"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!python script6.py 59"
      ],
      "metadata": {
        "id": "if7F-mIM-i_A",
        "outputId": "b952165a-7b2b-4951-d08c-42362ddf965e",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 16,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "fifty nine\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!wget https://raw.githubusercontent.com/nceder/qpb4e/main/code/Chapter%2011/n2w.py &> null   && echo Downloaded\n"
      ],
      "metadata": {
        "id": "7HdgL6Wplxnp",
        "outputId": "ed95d0a3-664a-4153-e8d6-d329738f6909",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 17,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloaded\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "```python\n",
        "# Listing 11.10 File n2w.py\n",
        "\n",
        "#! /usr/bin/env python3\n",
        "\"\"\"n2w: number to words conversion module: contains function\n",
        "   num2words. Can also be run as a script\n",
        "usage as a script: n2w num\n",
        "           (Convert a number to its English word description)\n",
        "           num: whole integer from 0 and 999,999,999,999,999 (commas are\n",
        "           optional)\n",
        "example: n2w 10,003,103\n",
        "           for 10,003,103 say: ten million three thousand one hundred three\n",
        "\"\"\"\n",
        "import sys, string, argparse\n",
        "_1to9dict = {'0': '', '1': 'one', '2': 'two', '3': 'three', '4': 'four',\n",
        "             '5': 'five', '6': 'six', '7': 'seven', '8': 'eight',\n",
        "             '9': 'nine'}\n",
        "_10to19dict = {'0': 'ten', '1': 'eleven', '2': 'twelve',\n",
        "               '3': 'thirteen', '4': 'fourteen', '5': 'fifteen',\n",
        "               '6': 'sixteen', '7': 'seventeen', '8': 'eighteen',\n",
        "               '9': 'nineteen'}\n",
        "_20to90dict = {'2': 'twenty', '3': 'thirty', '4': 'forty', '5': 'fifty',\n",
        "               '6': 'sixty', '7': 'seventy', '8': 'eighty', '9': 'ninety'}\n",
        "_magnitude_list = [(0, ''), (3, ' thousand '), (6, ' million '),\n",
        "                  (9, ' billion '), (12, ' trillion '),(15, '')]\n",
        "def num2words(num_string):\n",
        "    \"\"\"num2words(num_string): convert number to English words\"\"\"\n",
        "    if num_string == '0':\n",
        "        return 'zero'\n",
        "    num_string = num_string.replace(\",\", \"\")\n",
        "    num_length = len(num_string)\n",
        "    max_digits = _magnitude_list[-1][0]\n",
        "    if num_length > max_digits:\n",
        "\n",
        "        return \"Sorry, can't handle numbers with more than  \" \\\n",
        "               \"{0} digits\".format(max_digits)\n",
        "\n",
        "    num_string = '00' + num_string\n",
        "    word_string = ''\n",
        "    for mag, name in _magnitude_list:\n",
        "        if mag >= num_length:\n",
        "            return word_string\n",
        "        else:\n",
        "            hundreds, tens, ones = num_string[-mag-3], \\\n",
        "                 num_string[-mag-2], num_string[-mag-1]\n",
        "            if not (hundreds == tens == ones == '0'):\n",
        "                word_string = _handle1to999(hundreds, tens, ones) + \\\n",
        "                                            name + word_string\n",
        "def _handle1to999(hundreds, tens, ones):\n",
        "    if hundreds == '0':\n",
        "        return _handle1to99(tens, ones)\n",
        "    else:\n",
        "        return _1to9dict[hundreds] + ' hundred ' + _handle1to99(tens, ones)\n",
        "def _handle1to99(tens, ones):\n",
        "    if tens == '0':\n",
        "        return _1to9dict[ones]\n",
        "    elif tens == '1':\n",
        "        return _10to19dict[ones]\n",
        "    else:\n",
        "        return _20to90dict[tens] + ' ' + _1to9dict[ones]\n",
        "def test():\n",
        "    values = sys.stdin.read().split()\n",
        "    for val in values:\n",
        "        print(\"{0} = {1}\".format(val, num2words(val)))\n",
        "def main():\n",
        "    parser = argparse.ArgumentParser(usage=__doc__)\n",
        "    parser.add_argument(\"num\", nargs='*')\n",
        "    parser.add_argument(\"-t\", \"--test\", dest=\"test\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Test mode: reads from stdin\")\n",
        "    args = parser.parse_args()\n",
        "    if args.test:\n",
        "        test()\n",
        "    else:\n",
        "        try:\n",
        "            result = num2words(args.num[0])\n",
        "        except KeyError:\n",
        "            parser.error('argument contains non-digits')\n",
        "        else:\n",
        "            print(\"For {0}, say: {1}\".format(args.num[0], result))\n",
        "if __name__ == '__main__':\n",
        "    main()\n",
        "else:\n",
        "    print(\"n2w  loaded as a module\")\n",
        "```"
      ],
      "metadata": {
        "id": "fWe0kxu6LpHT"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Listing 11.11 File n2w.tst\n",
        "open(\"n2w.tst\", \"w\").write(\n",
        "    \"\"\"0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 98 99 100\n",
        "101 102 900 901 999\n",
        "999,999,999,999,999\n",
        "1,000,000,000,000,000\"\"\"\n",
        ")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "5ax5OjkcmBFl",
        "outputId": "23f3e672-26a9-4d67-88c7-6eaff0a4279d"
      },
      "execution_count": 18,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "127"
            ]
          },
          "metadata": {},
          "execution_count": 18
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "! python n2w.py --test < n2w.tst"
      ],
      "metadata": {
        "id": "1BHhwTmImLJW",
        "outputId": "4e24ebde-8898-4a38-cef7-93ac489dc080",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": 19,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "0 = zero\n",
            "1 = one\n",
            "2 = two\n",
            "3 = three\n",
            "4 = four\n",
            "5 = five\n",
            "6 = six\n",
            "7 = seven\n",
            "8 = eight\n",
            "9 = nine\n",
            "10 = ten\n",
            "11 = eleven\n",
            "12 = twelve\n",
            "13 = thirteen\n",
            "14 = fourteen\n",
            "15 = fifteen\n",
            "16 = sixteen\n",
            "17 = seventeen\n",
            "18 = eighteen\n",
            "19 = nineteen\n",
            "20 = twenty \n",
            "21 = twenty one\n",
            "98 = ninety eight\n",
            "99 = ninety nine\n",
            "100 = one hundred \n",
            "101 = one hundred one\n",
            "102 = one hundred two\n",
            "900 = nine hundred \n",
            "901 = nine hundred one\n",
            "999 = nine hundred ninety nine\n",
            "999,999,999,999,999 = nine hundred ninety nine trillion nine hundred ninety nine billion nine hundred ninety nine million nine hundred ninety nine thousand nine hundred ninety nine\n",
            "1,000,000,000,000,000 = Sorry, can't handle numbers with more than  15 digits\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Quick Check: Programs and modules\n",
        "\n",
        "What issue is the use of if `__name__ == \"__main__\":` meant to prevent, and how does it do that? Can you think of any other way to prevent this issue?\n",
        "\n",
        "#### Solution\n",
        "\n",
        "When Python loads a module, all of its code is executed. By using the pattern above, you can have certain code run only if it's being executed as the main script file.\n"
      ],
      "metadata": {
        "id": "jS4FD6myQdZn"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# 11.5 Lab 11: Creating a program\n",
        "\n",
        "In chapter 8, you created a version of the UNIX `wc` utility to count the lines, words, and characters in a file. Now that you have more tools at your disposal, refactor that program to make it work more like the original. In particular, the program should have options to show only lines (`-l`), only words (`-w`), and only characters (`-c`). If none of those options is given, all three stats are displayed. But if any of these options is present, only the specified stats are shown.\n",
        "\n",
        "For an extra challenge, have a look at the man page for `wc` on a Linux/UNIX system (`! man wc` in Colaboratory), and add the `-L` to show the longest line length. Feel free to try to implement the complete behavior as listed in the man page and test it against your system's `wc` utility."
      ],
      "metadata": {
        "id": "J7kKZRhjqN31"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Human (author) solution\n",
        "\n",
        "open(\"wc.py\", \"w\").write('''#!/usr/bin/env python3\n",
        "# File: word_count_program.py\n",
        "\"\"\" Reads a file and returns the number of lines, words,\n",
        "    and characters - similar to the UNIX wc utility\n",
        "\"\"\"\n",
        "import sys\n",
        "import argparse\n",
        "\n",
        "\n",
        "def main():\n",
        "    # initialze counts\n",
        "    line_count = 0\n",
        "    word_count = 0\n",
        "    char_count = 0\n",
        "    longest_line = 0\n",
        "\n",
        "    parser = argparse.ArgumentParser(usage=__doc__)\n",
        "    parser.add_argument(\"-c\", \"--characters\",\n",
        "                  action=\"store_true\", dest=\"chars\", default=False,\n",
        "                  help=\"display number of characters\")\n",
        "    parser.add_argument(\"-w\", \"--words\",\n",
        "                  action=\"store_true\", dest=\"words\", default=False,\n",
        "                  help=\"display number of words\")\n",
        "    parser.add_argument(\"-l\", \"--lines\",\n",
        "                  action=\"store_true\", dest=\"lines\", default=False,\n",
        "                  help=\"display number of lines\")\n",
        "    parser.add_argument(\"-L\", \"--longest\",\n",
        "                  action=\"store_true\", dest=\"longest\", default=False,\n",
        "                  help=\"display longest line length\")\n",
        "    parser.add_argument(\"filename\", help=\"read data from this file\")\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    filename = args.filename    # open the file\n",
        "    with  open(filename) as infile:\n",
        "        for line in infile:\n",
        "            line_count += 1\n",
        "            char_count += len(line)\n",
        "            words = line.split()\n",
        "            word_count += len(words)\n",
        "            if len(line) > longest_line:\n",
        "                longest_line = len(line)\n",
        "\n",
        "    default_args = any([getattr(args, _) for _ in ('chars', 'words', 'lines', 'longest')])\n",
        "\n",
        "    if not default_args:\n",
        "        args.chars = args.lines = args.words = True\n",
        "\n",
        "    if args.lines:\n",
        "        print(f\"{line_count:3}\", end=\" \")\n",
        "    if args.words:\n",
        "        print(f\"{word_count:4}\", end=\" \")\n",
        "    if args.chars:\n",
        "        print(f\"{char_count:4}\", end=\" \")\n",
        "    if args.longest:\n",
        "        print(f'{longest_line}', end=\" \")\n",
        "    print(f'{filename}')\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()\n",
        "''')"
      ],
      "metadata": {
        "id": "Q87ZMe0ZB1dm",
        "outputId": "15bc8d16-c469-4415-c238-11a8cbc2c0a3",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "1924"
            ]
          },
          "metadata": {},
          "execution_count": 7
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Generated by Copilot\n",
        "#!/usr/bin/env python3\n",
        "\n",
        "\"\"\" Reads a file and returns the number of lines, words,\n",
        "    and characters - similar to the UNIX wc utility\n",
        "\"\"\"\n",
        "\n",
        "with open('word_count.tst') as infile:\n",
        "    lines = infile.readlines()\n",
        "\n",
        "line_count = len(lines)\n",
        "word_count = sum(len(line.split()) for line in lines)\n",
        "char_count = sum(len(line) for line in lines)\n",
        "\n",
        "print(f\"File has {line_count} lines, {word_count} words, {char_count} characters\")\n"
      ],
      "metadata": {
        "id": "OkRlBVXnzy-E",
        "outputId": "5995133d-9ff0-4c7d-dfa2-f4fb7c49b3ec",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 211
        }
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "error",
          "ename": "FileNotFoundError",
          "evalue": "[Errno 2] No such file or directory: 'word_count.tst'",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-2-01dec0f38e48>\u001b[0m in \u001b[0;36m<cell line: 8>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      6\u001b[0m \"\"\"\n\u001b[1;32m      7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'word_count.tst'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0minfile\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      9\u001b[0m     \u001b[0mlines\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minfile\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreadlines\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'word_count.tst'"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Generated by Colaboratory\n",
        "# prompt: Refactor the code in the previous cell into a commandline program\n",
        "#         that works like the Unix wc utility, and supports the -l, -w, and\n",
        "#         -c options, and the -L option. Output should be similar to output of wc.\n",
        "\n",
        "#!/usr/bin/env python3\n",
        "\n",
        "\"\"\" Reads a file and returns the number of lines, words,\n",
        "    and characters - similar to the UNIX wc utility\n",
        "\"\"\"\n",
        "\n",
        "import argparse\n",
        "\n",
        "def main():\n",
        "    parser = argparse.ArgumentParser(usage=__doc__)\n",
        "    parser.add_argument(\"filename\", nargs='*')\n",
        "    parser.add_argument(\"-l\", \"--lines\", dest=\"lines\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show only line count\")\n",
        "    parser.add_argument(\"-w\", \"--words\", dest=\"words\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show only word count\")\n",
        "    parser.add_argument(\"-c\", \"--chars\", dest=\"chars\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show only character count\")\n",
        "    parser.add_argument(\"-L\", \"--longest\", dest=\"longest\",\n",
        "                      action='store_true', default=False,\n",
        "                      help=\"Show length of longest line\")\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    for filename in args.filename:\n",
        "        with open(filename) as infile:\n",
        "            lines = infile.readlines()\n",
        "\n",
        "        line_count = len(lines)\n",
        "        word_count = sum(len(line.split()) for line in lines)\n",
        "        char_count = sum(len(line) for line in lines)\n",
        "        longest_line_length = max(len(line) for line in lines)\n",
        "\n",
        "        if args.lines:\n",
        "            print(f\"{line_count} {filename}\")\n",
        "        elif args.words:\n",
        "            print(f\"{word_count} {filename}\")\n",
        "        elif args.chars:\n",
        "            print(f\"{char_count} {filename}\")\n",
        "        elif args.longest:\n",
        "            print(f\"{longest_line_length} {filename}\")\n",
        "        else:\n",
        "            print(f\"{line_count} {word_count} {char_count} {filename}\")\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()\n"
      ],
      "metadata": {
        "id": "b98Dnx_Z8lxC"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Generated by Copilot\n",
        "# wc.py\n",
        "\n",
        "import argparse\n",
        "\n",
        "def count_stats(file_path):\n",
        "    with open(file_path) as infile:\n",
        "        lines = infile.readlines()\n",
        "\n",
        "    line_count = len(lines)\n",
        "    word_count = sum(len(line.split()) for line in lines)\n",
        "    char_count = sum(len(line) for line in lines)\n",
        "    max_line_length = max(len(line) for line in lines)\n",
        "\n",
        "    return line_count, word_count, char_count, max_line_length\n",
        "\n",
        "def main():\n",
        "    parser = argparse.ArgumentParser(description='Count lines, words, and characters in a file.')\n",
        "    parser.add_argument('file', help='File to count')\n",
        "    parser.add_argument('-l', '--lines', action='store_true', help='Count lines')\n",
        "    parser.add_argument('-w', '--words', action='store_true', help='Count words')\n",
        "    parser.add_argument('-c', '--chars', action='store_true', help='Count characters')\n",
        "    parser.add_argument('-L', '--max-line-length', action='store_true', help='Print length of the longest line')\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    line_count, word_count, char_count, max_line_length = count_stats(args.file)\n",
        "\n",
        "    if args.lines:\n",
        "        print(f'Lines: {line_count}')\n",
        "    if args.words:\n",
        "        print(f'Words: {word_count}')\n",
        "    if args.chars:\n",
        "        print(f'Characters: {char_count}')\n",
        "    if args.max_line_length:\n",
        "        print(f'Max line length: {max_line_length}')\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()"
      ],
      "metadata": {
        "id": "rVB0y7prB7mA"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# wc.py\n",
        "\n",
        "import argparse\n",
        "import os\n",
        "\n",
        "def count_stats(file_path):\n",
        "    with open(file_path) as infile:\n",
        "        lines = infile.readlines()\n",
        "\n",
        "    line_count = len(lines)\n",
        "    word_count = sum(len(line.split()) for line in lines)\n",
        "    byte_count = os.path.getsize(file_path)\n",
        "    max_line_length = max(len(line) for line in lines)\n",
        "\n",
        "    return line_count, word_count, byte_count, max_line_length\n",
        "\n",
        "def main():\n",
        "    parser = argparse.ArgumentParser(description='Count lines, words, and bytes in a file.')\n",
        "    parser.add_argument('file', help='File to count')\n",
        "    parser.add_argument('-l', '--lines', action='store_true', help='Count lines')\n",
        "    parser.add_argument('-w', '--words', action='store_true', help='Count words')\n",
        "    parser.add_argument('-c', '--bytes', action='store_true', help='Count bytes')\n",
        "    parser.add_argument('-L', '--max-line-length', action='store_true', help='Print length of the longest line')\n",
        "    args = parser.parse_args()\n",
        "\n",
        "    line_count, word_count, byte_count, max_line_length = count_stats(args.file)\n",
        "\n",
        "    if args.lines:\n",
        "        print(line_count, end=' ')\n",
        "    if args.words:\n",
        "        print(word_count, end=' ')\n",
        "    if args.bytes:\n",
        "        print(byte_count, end=' ')\n",
        "    if args.max_line_length:\n",
        "        print(max_line_length, end=' ')\n",
        "    if not any([args.lines, args.words, args.bytes, args.max_line_length]):\n",
        "        print(f'{line_count} {word_count} {byte_count} {args.file}')\n",
        "    else:\n",
        "        print(args.file)\n",
        "\n",
        "if __name__ == '__main__':\n",
        "    main()"
      ],
      "metadata": {
        "id": "POA5bYByFS9f"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# make file executable\n",
        "! chmod +x wc.py"
      ],
      "metadata": {
        "id": "_eAbovX1uabS"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# run on the file itself\n",
        "\n",
        "! /content/wc.py  -L wc.py"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Kz3TfeD-vGlM",
        "outputId": "2febbb44-4583-46dc-fb01-8bcd30a18345"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "91 wc.py\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# run wc on file itself\n",
        "! wc  wc.py"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Xfd-DfUTyFwy",
        "outputId": "1650c151-82e6-4e30-a408-b3f91b4b76fd"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "  58  173 1882 wc.py\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# run on README in sample_data\n",
        "\n",
        "! /content/wc.py  sample_data/README.md"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "YbhDaMdTx4e1",
        "outputId": "0472a114-ccb4-43ea-89f3-6c5a12aea575"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "  19   80  930"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# run wc on sample_data/README.md\n",
        "! wc   sample_data/README.md"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ShphasEPvB9P",
        "outputId": "017e2850-3a51-471c-b32d-c8be66a0f99a"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            " 19  80 930 sample_data/README.md\n"
          ]
        }
      ]
    }
  ]
}